home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_300 / 365_02 / tinyprnt.c < prev    next >
Text File  |  1992-04-04  |  5KB  |  231 lines

  1. /* tinyprnt.c */
  2.  
  3. #if OSK
  4. #define sprintf Sprintf
  5. #endif
  6.  
  7. /* This is a limited version of sprintf().  It is useful for Minix-PC and
  8.  * Coherent-286 because those systems are both limited to 64k+64k and the
  9.  * standard sprintf() is just too damn big.
  10.  *
  11.  * It should also be useful for OS-9 because OS-9's sprintf() doesn't
  12.  * understand the true meaning of asterisks in a format string.  This one
  13.  * does.
  14.  */
  15.  
  16. /* Place-holders in format strings look like "%<pad><clip><type>".
  17.  *
  18.  * The <pad> adds space to the front (or, if negative, to the back) of the
  19.  * output value, to pad it to a given width.  If <pad> is absent, then 0 is
  20.  * assumed.  If <pad> is an asterisk, then the next argument is assumed to
  21.  * be an (int) which used as the pad width.
  22.  *
  23.  * The <clip> string can be absent, in which case no clipping is done.
  24.  * However, if it is present, then it should be either a "." followed by
  25.  * a number, or a "." followed by an asterisk.  The asterisk means that the
  26.  * next argument is an (int) which should be used as the pad width.  Clipping
  27.  * only affects strings; for other data types it is ignored.
  28.  *
  29.  * The <type> is one of "s" for strings, "c" for characters (really ints that
  30.  * are assumed to be legal char values), "d" for ints, "ld" for long ints, or
  31.  * "%" to output a percent sign.
  32.  */
  33.  
  34. /* NOTE: Variable argument lists are handled by direct stack-twiddling. Sorry! */
  35.  
  36. static void cvtnum(buf, num, base)
  37.     char        *buf;    /* where to store the number */
  38.     unsigned long    num;    /* the number to convert */
  39.     int        base;    /* either 8, 10, or 16 */
  40. {
  41.     static char    digits[] = "0123456789abcdef";
  42.     unsigned long    tmp;
  43.  
  44.     /* if the number is 0, then just stuff a "0" into the buffer */
  45.     if (num == 0L)
  46.     {
  47.         buf[0] = '0';
  48.         buf[1] = '\0';
  49.         return;
  50.     }
  51.  
  52.     /* use tmp to figure out how many digits we'll need */
  53.     for (tmp = num; tmp > 0; tmp /= base)
  54.     {
  55.         buf++;
  56.     }
  57.  
  58.     /* mark the spot that will be the end of the string */
  59.     *buf = '\0';
  60.  
  61.     /* generate all digits, as needed */
  62.     for (tmp = num; tmp > 0; tmp /= base)
  63.     {
  64.         *--buf = digits[tmp % base];
  65.     }
  66. }
  67.  
  68. int sprintf(buf, fmt, argref)
  69.     char    *buf;    /* where to deposit the formatted output */
  70.     char    *fmt;    /* the format string */
  71.     int    argref;    /* the first argument is located at &argref */
  72. {
  73.     char    *argptr;/* pointer to next argument on the stack */
  74.     int    pad;    /* value of the pad string */
  75.     int    clip;    /* value of the clip string */
  76.     long    num;    /* a binary number being converted to ASCII digits */
  77.     long    digit;    /* used during conversion */
  78.     char    *src, *dst;
  79.  
  80.     /* make argptr point to the first argument after the format string */
  81.     argptr = (char *)&argref;
  82.  
  83.     /* loop through the whole format string */
  84.     while (*fmt)
  85.     {
  86.         /* if not part of a place-holder, then copy it literally */
  87.         if (*fmt != '%')
  88.         {
  89.             *buf++ = *fmt++;
  90.             continue;
  91.         }
  92.  
  93.         /* found a place-holder!  Get <pad> value */
  94.         fmt++;
  95.         if ('*' == *fmt)
  96.         {
  97.             pad = *((int *)argptr)++;
  98.             fmt++;
  99.         }
  100.         else if (*fmt == '-' || (*fmt >= '0' && *fmt <= '9'))
  101.         {
  102.             pad = atol(fmt);
  103.             do
  104.             {
  105.                 fmt++;
  106.             } while (*fmt >= '0' && *fmt <= '9');
  107.         }
  108.         else
  109.         {
  110.             pad = 0;
  111.         }
  112.  
  113.         /* get a <clip> value */
  114.         if (*fmt == '.')
  115.         {
  116.             fmt++;
  117.             if ('*' == *fmt)
  118.             {
  119.                 clip = *((int *)argptr)++;
  120.                 fmt++;
  121.             }
  122.             else if (*fmt >= '0' && *fmt <= '9')
  123.             {
  124.                 clip = atol(fmt);
  125.                 do
  126.                 {
  127.                     fmt++;
  128.                 } while (*fmt >= '0' && *fmt <= '9');
  129.             }
  130.         }
  131.         else
  132.         {
  133.             clip = 0;
  134.         }
  135.  
  136.         /* handle <type>, possibly noticing <clip> */
  137.         switch (*fmt++)
  138.         {
  139.           case 'c':
  140.             buf[0] = *((int *)argptr)++;
  141.             buf[1] = '\0';
  142.             break;
  143.  
  144.           case 's':
  145.             src = *((char **)argptr)++;
  146.             if (!src)
  147.             {
  148.                 src = "(null)";
  149.             }
  150.             if (clip)
  151.             {
  152.                 strncpy(buf, src, clip);
  153.                 buf[clip] = '\0';
  154.             }
  155.             else
  156.             {
  157.                 strcpy(buf, src);
  158.             }
  159.             break;
  160.  
  161.           case 'l':
  162.             fmt++; /* to skip the "d" in "%ld" */
  163.             num = *((long *)argptr)++;
  164.             dst = buf;
  165.             if (num < 0)
  166.             {
  167.                 *dst++ = '-';
  168.                 num = -num;
  169.             }
  170.             cvtnum(dst, num, 10);
  171.             break;
  172.  
  173.           case 'x':
  174.             num = *((int *)argptr)++;
  175.             cvtnum(buf, num, 16);
  176.             break;
  177.  
  178.           case 'd':
  179.             num = *((int *)argptr)++;
  180.             dst = buf;
  181.             if (num < 0)
  182.             {
  183.                 *dst++ = '-';
  184.                 num = -num;
  185.             }
  186.             cvtnum(dst, num, 10);
  187.             break;
  188.  
  189.           default:
  190.             buf[0] = fmt[-1];
  191.             buf[1] = '\0';
  192.         }
  193.  
  194.         /* now fix the padding, if the value is too short */
  195.         clip = strlen(buf);
  196.         if (pad < 0)
  197.         {
  198.             /* add spaces after the value */
  199.             pad = -pad - clip;
  200.             for (buf += clip; pad > 0; pad--)
  201.             {
  202.                 *buf++ = ' ';
  203.             }
  204.             *buf = '\0';
  205.         }
  206.         else
  207.         {
  208.             /* add spaces before the value */
  209.             pad -= clip;
  210.             if (pad > 0)
  211.             {
  212.                 src = buf + clip;
  213.                 dst = src + pad;
  214.                 *dst = '\0';
  215.                 while (src > buf)
  216.                 {
  217.                     *--dst = *--src;
  218.                 }
  219.                 while (dst > buf)
  220.                 {
  221.                     *--dst = ' ';
  222.                 }
  223.             }
  224.             buf += strlen(buf);
  225.         }
  226.     }
  227.  
  228.     /* mark the end of the output string */
  229.     *buf = '\0';
  230. }
  231.